﻿/* 
 *  <copyright file="UserGameService.cs" company="Wesley Jowitt">
 *  
 *  SobrietyEngine: Copyright (c) 2011 Wesley Jowitt
 *  
 *  This software is distributed under a software license.
 *   * As of the creation time of this file, the license in use is the Microsoft Permissive License (Ms-PL) 
 *    * The license can be viewed at:
 *     * License.Txt in the root folder of this project
 *      * http://sobrietyengine.codeplex.com/license
 *       * http://www.microsoft.com/opensource/licenses.mspx
 *       
 *  </copyright>
 *   */

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;

using SobrietyEngine.Events;
using SobrietyEngine.Events.Input;
using SobrietyEngine.Events.User;
using SobrietyEngine.Input;
using SobrietyEngine.Input.Devices;

namespace SobrietyEngine.User
{
    //TODO: add code to check to see if we have already attached a controller to a user
    //need to handle keyboards, mice, touchscreens
    //check to see if user is signed in / handle xbox live account stuff
    //handle accidental control disconnects
    //set worldUp storage locations
    //load / save user data
    public class UserGameService: GameComponent, IUserGameService, IGameComponent, IEventListener
    {
        IEventRouter eventRouter;
        //Dictionary<String, User> usersByName = new Dictionary<string, User>();
        public List<IUser> Users {get; set; }
        public List<GamepadEnums.GamepadButton> JoinOnButton { get; set; }
        public int MaxLocalUsers { get; set; }
        public Boolean ShowGuideOnJoin { get; set; }
        public Boolean AllowNewUser { get; set; }

        public List<String> AvailablePlayerNames = new List<string>() { "Player1", "Player2", "Player3", "Player4" };
        public List<String> ActivePlayerNames = new List<string>();

        IUser keyboardUser = null;

        public UserGameService(Game game)
            : base(game)
        {
            Game.Services.AddService(typeof(IUserGameService), this);

            JoinOnButton = new List<GamepadEnums.GamepadButton>();
            JoinOnButton.Add(GamepadEnums.GamepadButton.Start);
            JoinOnButton.Add(GamepadEnums.GamepadButton.Guide);
            Users = new List<IUser>();            
            eventRouter = (IEventRouter)Game.Services.GetService(typeof(IEventRouter));
            MaxLocalUsers = 1;
            ShowGuideOnJoin = true;
            AllowNewUser = true;
        }

        public override void Initialize()
        {
            base.Initialize();
            RegisterEventListeners();
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            UnregisterEventListeners();
        }

        public virtual void RegisterEventListeners()
        {
            eventRouter.AddEventListener(typeof(DeviceConnected), this);
            eventRouter.AddEventListener(typeof(DeviceDisconnected), this);
        }

        public virtual void UnregisterEventListeners()
        {
            eventRouter.RemoveEventListener(this);
        }

        public void HandleEvent(Event e)
        {
            if(e.Data.GetType() == typeof(DeviceConnected))
            {
                DeviceConnected dc = (DeviceConnected)e.Data;
                IUser user = null;

                //keybaord device is treated a PC keyboard, attached to first User if available
                if (Users.Count > 0 && dc.InputDevice is KeyboardDevice)
                {
                    //attach keyboard to fisrt active player
                    Users[0].InputDevices.Add(dc.InputDevice);
                    return;
                } 

                //if we have a keyboard user, attach next gamepad to it
                else if (keyboardUser != null && dc.InputDevice is GamepadDevice)
                {
                    keyboardUser.InputDevices.Add(dc.InputDevice);
                    return;
                }

                //if we need to create a user
                if (AvailablePlayerNames.Count > 0)
                {
                    user = new User(AvailablePlayerNames[0]);
                    if (dc.InputDevice is KeyboardDevice)
                        keyboardUser = user;

                    ActivePlayerNames.Add(AvailablePlayerNames[0]);
                    AvailablePlayerNames.RemoveAt(0);
                }
                else
                {
                    //default no name user. will likely cause 
                    //GUID problems. need to com eup with better solution
                    user = new User();
                }

                user.Active = true;
                user.InputDevices.Add(dc.InputDevice);
                eventRouter.RaiseEvent(this, new UserConnected(user.Guid));
                Users.Add(user);
            }

            else if(e.Data.GetType() == typeof(DeviceDisconnected))
            {
                DeviceDisconnected dc = (DeviceDisconnected)e.Data;
                User toRemove = null;
                foreach (User u in Users)
                {
                    if (u.InputDevices.Contains(dc.InputDevice))
                    {
                        toRemove = u;
                    }
                }
                if (toRemove != null)
                {
                    Users.Remove(toRemove);
                    eventRouter.RaiseEvent(this, new UserDisconnected(toRemove.Guid));
                }
            }
        }
    }
}
